﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using MoveNext.IO.Grf;
using System.IO;
using System.Diagnostics;
using MoveNext.GrfFileManager.Properties;

namespace MoveNext.GrfFileManager
{
    public partial class MainForm : Form
    {
        private string grfFile;
        SortableBindingList<FileEntry> dataSource;
        private Dictionary<string, Icon> shellIcons;

        public MainForm()
        {
            InitializeComponent();
            this.ProgressVisible(false);
            this.dgv.AutoGenerateColumns = false;
            this.lblStatus.Text = string.Empty;
            this.Text = Application.ProductName;
            FileInfo fi = new FileInfo(Path.GetTempPath() + "dummy");
            using (FileStream fs = fi.Create()) ;
            System.Drawing.Icon icon = ShellIcon.GetSmallIcon(fi.FullName);
            ((DataGridViewImageColumn)this.dgv.Columns["IconColumn"]).Image = icon.ToBitmap();
            this.tsmiExtractFiles.Image = Resources.ICON_BOX_EMPTY.ToBitmap();
            this.tsmiExtractFilesWithFolders.Image = Resources.ICON_BOX_EMPTY.ToBitmap();
        }

        public MainForm(string grfFile)
            : this()
        {
            this.grfFile = grfFile;
            this.ReadGrf();
        }

        private void ReadGrf()
        {
            this.lblStatus.Text = string.Format("Reading file \"{0}\"...", this.grfFile);
            Application.DoEvents();
            try
            {
                FileEntry[] entrys;
                this.dataSource = new SortableBindingList<FileEntry>();
                using (FileStream fs = new FileStream(grfFile, FileMode.Open, FileAccess.Read))
                using (GrfReader gr = new GrfReader(fs))
                {
                    entrys = gr.ReadFileEntrys();
                }
                foreach (FileEntry entry in entrys)
                {
                    this.dataSource.Add(entry);
                }
                this.GetShellIcons();
                dgv.DataSource = this.dataSource;
                lblStatus.Text = string.Format("{0} file(s) found.", this.dataSource.Count);
                this.Text = string.Format("{0} - {1}", Application.ProductName, this.grfFile);
            }
            catch (Exception ex)
            {
                this.lblStatus.Text = "";
                MessageBox.Show(ex.Message, ex.GetType().Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void GetShellIcons()
        {
            FileInfo fi;
            string temp = Path.GetTempPath();
            this.shellIcons = new Dictionary<string, Icon>();
            foreach (FileEntry entry in this.dataSource)
            {
                if (!string.IsNullOrEmpty(entry.FileExtension) && !this.shellIcons.ContainsKey(entry.FileExtension))
                {
                    fi = new FileInfo(temp + entry.FileName);
                    using (FileStream fs = fi.Create()) ;
                    this.shellIcons.Add(entry.FileExtension, ShellIcon.GetSmallIcon(fi.FullName));
                }
            }

            //foreach (DataGridViewRow row in this.dgv.Rows)
            //{
            //    string extension = row.Cells["FileExtension"].Value.ToString();
            //    if (!string.IsNullOrEmpty(extension))
            //    {
            //        row.Cells["IconColumn"].Value = this.shellIcons[extension];
            //    }
            //}
            //this.dgv.RefreshEdit();
            //this.dgv.Update();
            //this.dgv.Refresh();

        }

        private void dgv_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            FileEntry fileEntry;
            if (e.Value != null)
            {
                if (e.ColumnIndex == dgv.Columns["FileExtension"].Index)
                {
                    if ((fileEntry = dgv.Rows[e.RowIndex].DataBoundItem as FileEntry) != null)
                    {
                        Icon icon;
                        if (this.shellIcons.TryGetValue(fileEntry.FileExtension, out icon))
                        {
                            this.dgv.Rows[e.RowIndex].Cells["IconColumn"].Value = icon;
                        }
                    }
                    e.Value = e.Value.ToString().Replace(".", "").ToUpper();
                }
                else if (e.ColumnIndex == dgv.Columns["CompressedLength"].Index || e.ColumnIndex == dgv.Columns["UncompressedLength"].Index)
                {

                    decimal size = (int)e.Value;
                    decimal fsize;
                    if (size > 1024)
                    {
                        fsize = size / 1024m;
                        e.Value = string.Format("{0:#,0} KB", fsize);
                    }
                    else
                    {
                        e.Value = string.Format("{0} Bytes", size);
                    }
                }
            }
        }

        private void dgv_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex == dgv.Columns["FullName"].Index)
            {
                FileEntry fileEntry = dgv.Rows[e.RowIndex].DataBoundItem as FileEntry;
                if (fileEntry != null)
                {
                    string path;
                    using (FileStream fs = new FileStream(grfFile, FileMode.Open, FileAccess.Read))
                    using (GrfReader gr = new GrfReader(fs))
                    {
                        path = Path.GetTempPath();
                        gr.CreateFile(fileEntry, path, false, true);
                    }
                    Process.Start(path + fileEntry.FileName);
                }
            }
        }

        private List<FileEntry> GetSelectedFileEntrys()
        {
            List<FileEntry> fileEntrys = new List<FileEntry>();
            if (this.dgv.SelectedRows.Count > 0)
            {
                foreach (DataGridViewRow row in this.dgv.SelectedRows)
                {
                    fileEntrys.Add((FileEntry)row.DataBoundItem);
                }
            }
            return fileEntrys;
        }

        private void ExtractFiles(bool useGrfFolder)
        {
            SortableBindingList<ExtractErrorLog> errorLog = new SortableBindingList<ExtractErrorLog>();
            List<FileEntry> fileEntrys = this.GetSelectedFileEntrys();
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.FileName = "folder";
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                this.progress.Maximum = fileEntrys.Count;
                this.progress.Value = 0;
                this.progress.ProgressBar.Style = ProgressBarStyle.Continuous;
                this.dgv.Enabled = false;
                try
                {
                    FileInfo fi = new FileInfo(dlg.FileName);
                    bool overwrite = MessageBox.Show("Overwrite existing files?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes;
                    using (FileStream fs = new FileStream(grfFile, FileMode.Open, FileAccess.Read))
                    using (GrfReader gr = new GrfReader(fs))
                    {
                        this.ProgressVisible(true);
                        for (int i = 0; i < fileEntrys.Count; i++)
                        {
                            try
                            {
                                lblStatus.Text = string.Format("Extracting file \"{0}\"...", fileEntrys[i].FullName);
                                Application.DoEvents();
                                gr.CreateFile(fileEntrys[i], fi.Directory.FullName, useGrfFolder, overwrite);
                            }
                            catch (Exception ex)
                            {
                                errorLog.Add(new ExtractErrorLog(fileEntrys[i].FullName, ex.GetType().Name, ex.Message));
                            }
                            finally
                            {
                                this.progress.PerformStep();
                                Application.DoEvents();
                            }
                        }
                        lblStatus.Text = string.Format("{0} file(s) extracted to \"{1}\".", fileEntrys.Count - errorLog.Count, fi.Directory.FullName);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, ex.GetType().Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                finally
                {
                    this.ProgressVisible(false);
                    this.dgv.Enabled = true;
                }
            }
            if (errorLog.Count > 0)
            {
                ExtractErrorLogViewer form = new ExtractErrorLogViewer(errorLog);
                form.Show();
            }
        }

        private void ProgressVisible(bool visible)
        {
            this.progress.Visible = visible;
            this.progress.Width = visible ? 120 : 0;
        }



        private void OpenFile()
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Multiselect = false;
            dlg.Filter = @"GRF File (*.grf)|*.grf|All files (*.*)|*.*";
            if (dlg.ShowDialog() == DialogResult.OK && File.Exists(dlg.FileName))
            {
                this.grfFile = dlg.FileName;
                this.ReadGrf();
            }
        }

        private void dgv_CellMouseDown(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                if (this.dgv.SelectedRows.Count == 1)
                {
                    this.dgv.ClearSelection();
                    this.dgv.Rows[e.RowIndex].Selected = true;
                }
            }
        }

        private void tsmiSelectAll_Click(object sender, EventArgs e)
        {
            this.dgv.SelectAll();
        }

        private void tsmiExtractFiles_Click_1(object sender, EventArgs e)
        {
            try
            {
                this.ExtractFiles(false);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, ex.GetType().Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void tsmiExtractFilesWithFolders_Click(object sender, EventArgs e)
        {
            try
            {
                this.ExtractFiles(true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, ex.GetType().Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void tsmiOpen_Click(object sender, EventArgs e)
        {
            this.OpenFile();
        }

        private void tsmiExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void tsmiAbout_Click(object sender, EventArgs e)
        {
            AboutBox1 form = new AboutBox1();
            form.Show();
        }



    }
}
